package parser;

import lexer.Token;
import lexer.TokenType;
import lexer.Tokenizer;
import parser.symbol.*;
import utils.CompileError;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Stack;

import static parser.symbol.Table.llvm;
import static parser.symbol.Table.regCnt;

public class Parser {
    Instruction instruction;
    Tokenizer tokenizer; //词法分析器
    public Token token; // 偷看的token
    Stack<String> breakStk, continueStk; // 放置break和continue要跳转的label

    boolean needRetExp, hasRet;

    public Parser(Tokenizer tokenizer) {
        instruction = new Instruction();
        this.tokenizer = tokenizer;
        breakStk = new Stack<>();
        continueStk = new Stack<>();
    }

    private void nextToken() {
        token = tokenizer.getNextToken();
        System.out.println(token);
    }

    private void backToLastToken() {
        token = tokenizer.backToLastToken();
//        System.out.println("回退一个token，当前为"+token);
    }

    public void analyse() throws CompileError {
        nextToken();
        analyseCompUnit();
    }

    /**
     * CompUnit     -> [CompUnit] (Decl | FuncDef)
     * 有1-n个 (Decl | FuncDef)
     * 0个或多个Decl  Decl为const int ident=或 int ident=
     * FuncDef为 int ident () Block // 开始入口的函数是main
     * 若ident不是main，就是全局变量定义
     *
     * @throws CompileError
     */
    private void analyseCompUnit() throws CompileError {
        while (token.equalTo("int") || token.equalTo("void") || token.equalTo("const")) {
            nextToken(); // int/void/const
            nextToken(); // main/fun/int
            Token third = token; // 不是(的话就是全局变量
            backToLastToken();
            backToLastToken();
            // int main()   void fun() 函数定义第三个一定是 ( 否则就是全局变量
            while (!third.equalTo("(")) {//不是函数
                analyseGlobalDecl();//全局变量
                nextToken();
                nextToken();
                third = token;
                backToLastToken();
                backToLastToken();
            }
            analyseFuncDef();
        }
    }

    /**
     * Decl         -> ConstDecl | VarDecl
     *
     * @throws CompileError
     */
    private void analyseDecl() throws CompileError {
        if (token.equalTo("const")) {
            analyseConstDecl();
        } else if (token.equalTo("int")) {
            analyseVarDecl();
        } else {
            throw new CompileError("期望const或int，实际为" + token.value());
        }
    }

    /**
     * ConstDecl    -> 'const' BType ConstDef { ',' ConstDef } ';'
     *
     * @throws CompileError
     */
    private void analyseConstDecl() throws CompileError {
        if (token.equalTo("const")) {// const
            nextToken();
            analyseBType(); // BType (int)
            analyseConstDef(); // ConstDef
            while (token.equalTo(",")) { // ,
                nextToken();
                analyseConstDef(); // ConstDef
            }
            if (token.equalTo(";")) {// ;
                nextToken();
            } else {
                throw new CompileError("期望;，实际为" + token.value());
            }
        } else {
            throw new CompileError("期望const，实际为" + token.value());
        }
    }

    /**
     * BType        -> 'int'
     *
     * @throws CompileError
     */
    private void analyseBType() throws CompileError {
        if (token.equalTo("int")) {
            nextToken();
        } else {
            throw new CompileError("期望int，实际为" + token.value());
        }
    }

    /**
     * ConstDef     -> Ident '=' ConstInitVal
     * ConstDef     -> Ident { '[' ConstExp ']' } '=' ConstInitVal
     *
     * @throws CompileError
     */
    private void analyseConstDef() throws CompileError {
        String tokenName = analyseIdent(); // Ident合法
        Symbol newSymbol;
        if (token.equalTo("[")) {//是数组  Ident { '[' ConstExp ']' }
            int dim = 0, length = 1;
            ArrayList<Integer> size = new ArrayList<>();
            while (token.equalTo("[")) {
                nextToken();
                int value = analyseGlobalExp(false); // 用计算常量表达式的函数
                size.add(value);
                length *= value;
                dim++;
                if (token.equalTo("]")) {
                    nextToken();
                } else {
                    throw new CompileError("期望]，实际为" + token);
                }
            }// a[2][2][3]={{{1,2,3},{4,5,6}},{{1,2,3},{4,5,6}}}的a[2][2][3]结束
            newSymbol = instruction.alloca(tokenName, length);// 分配内存，登记到符号表
            newSymbol.setConst(true); // 是常量
            newSymbol.setName(tokenName);// 变量名
            ((MyArray) newSymbol).setDimAndSize(dim, size);//维度、每个维度的长度
            if (token.equalTo("=")) {//1或者dim个左括号  '{' [ ConstInitVal { ',' ConstInitVal } ] '}'
                nextToken();
                ArrayList<Symbol> content = ((MyArray) newSymbol).getContent();
                int depth = -1;
                int[] pos = new int[dim];
                Arrays.fill(pos, -1);
                Stack<String> match = new Stack<>();
                do {
                    if (token.equalTo("{")) {
                        nextToken();
                        depth++;
                        pos[depth]++;
                        match.push("{");
                    } else if (token.equalTo("}")) {
                        depth--;
                        if (depth != -1) {//不是最外围
                            pos[depth]++;
                        }
                        Arrays.fill(pos, depth + 1, dim, -1);//退回一维后面的重置为-1重新计数
                        if (match.peek().equals("{")) {
                            match.pop();
                        } else {
                            throw new CompileError("右括号与左括号不匹配" + token);
                        }
                        nextToken();
                        if (match.empty()) {
                            break;
                        }
                        if (token.equalTo(",")) {//逗号只会出现在右括号后面或者ConstExp后面
                            nextToken();
                        }
                    } else {
                        Symbol tmpSymbol = analyseConstExp();
                        tmpSymbol.setConst(true);
                        int idx = 0, postMul = 1;
                        for (int i = dim - 1; i >= 0; i--) {//求后缀积
                            idx += pos[i] * postMul;
                            postMul *= size.get(i);
                        }
                        content.set(idx, tmpSymbol);
                        content.set(idx, tmpSymbol);
                        Symbol to = instruction.getElementPtr(((MyArray) newSymbol), new MyNumber(idx));
                        instruction.store(tmpSymbol, to);
                        pos[depth]++;
                        if (token.equalTo(",")) {//逗号只会出现在右括号后面或者ConstExp后面
                            nextToken();
                        }
                    }
                } while (!match.empty());
                System.out.println("***debug数组内容：" + ((MyArray) newSymbol).getContent());
            }
        } else if (token.equalTo("=")) {//非
            newSymbol = instruction.alloca(tokenName); // 分配内存，登记到符号表
            newSymbol.setConst(true); // 是常量
            newSymbol.setName(tokenName);// 变量名
            nextToken();
            Symbol symbol = analyseConstInitVal();
            if (symbol instanceof MyNumber) {
                newSymbol.setInitVal(((MyNumber) symbol).getValue());
            } else if (symbol.isConst()) {
                newSymbol.setInitVal(symbol.getInitVal());
            } else {
                throw new CompileError("const定义引用非const");
            }
            instruction.store(symbol, newSymbol);
        } else {
            throw new CompileError("期望=或[，实际为" + token.value());
        }
    }

    /**
     * ConstInitVal -> ConstExp
     * ConstInitVal -> ConstExp  |
     *
     * @throws CompileError
     */
    private Symbol analyseConstInitVal() throws CompileError {
        return analyseConstExp();
    }

    /**
     * ConstExp     -> AddExp
     *
     * @throws CompileError
     */
    private Symbol analyseConstExp() throws CompileError {
        Symbol symbol = analyseAddExp();
        if (!symbol.isConst()) {
            throw new CompileError("变量不能定义常量");
        }
        return symbol;
    }

    /**
     * VarDecl      -> BType VarDef { ',' VarDef } ';'
     *
     * @throws CompileError
     */
    private void analyseVarDecl() throws CompileError {
        analyseBType();
        analyseVarDef();
        while (token.equalTo(",")) {
            nextToken();
            analyseVarDef();
        }
        if (token.equalTo(";")) {
            nextToken();
        } else {
            throw new CompileError("期望;，实际为" + token.value());
        }
    }

    /**
     * VarDef       -> Ident | Ident '=' InitVal
     * VarDef       -> Ident { '[' ConstExp ']' }  | Ident { '[' ConstExp ']' } '=' InitVal // [changed]
     *
     * @throws CompileError
     */
    private void analyseVarDef() throws CompileError {
        Token ident = token;
        String identName = analyseIdent(); // Ident合法
        Symbol newSymbol;
        if (token.equalTo("[")) {//是数组
            int dim = 0, length = 1;
            ArrayList<Integer> size = new ArrayList<>();
            while (token.equalTo("[")) {
                nextToken();
                int value = analyseGlobalExp(false); // 用计算常量表达式的函数
                if (value < 0)
                    throw new CompileError("数组下标为负值" + value);
                size.add(value);
                length *= value;
                dim++;
                if (token.equalTo("]")) {
                    nextToken();
                } else {
                    throw new CompileError("期望]，实际为" + token);
                }
            }// a[2][2][3]={{{1,2,3},{4,5,6}},{{1,2,3},{4,5,6}}}的a[2][2][3]结束
            newSymbol = instruction.alloca(identName, length);// 分配内存，登记到符号表
            newSymbol.setName(identName);// 变量名
            ((MyArray) newSymbol).setDimAndSize(dim, size);
            if (token.equalTo("=")) {//1或者dim个左括号  '{' [ ConstInitVal { ',' ConstInitVal } ] '}'
                nextToken();
                ArrayList<Symbol> content = ((MyArray) newSymbol).getContent();
                int depth = -1;
                int[] pos = new int[dim];
                Arrays.fill(pos, -1);
                Stack<String> match = new Stack<>();
                do {
                    if (token.equalTo("{")) {
                        nextToken();
                        depth++;
                        pos[depth]++;
                        match.push("{");
                    } else if (token.equalTo("}")) {
                        depth--;
                        if (depth != -1) {//不是最外围
                            pos[depth]++;
                        }
                        Arrays.fill(pos, depth + 1, dim, -1);//退回一维后面的重置为-1重新计数
                        if (match.peek().equals("{")) {
                            match.pop();
                        } else {
                            throw new CompileError("右括号与左括号不匹配" + token);
                        }
                        nextToken();
                        if (match.empty()) {
                            break;
                        }
                        if (token.equalTo(",")) {//逗号只会出现在右括号后面或者ConstExp后面
                            nextToken();
                        }
                    } else {
                        Symbol tmpSymbol = analyseExp();//Exp
                        int idx = 0, postMul = 1;
                        for (int i = dim - 1; i >= 0; i--) {//后缀积
                            idx += pos[i] * postMul;
                            postMul *= size.get(i);
                        }
                        content.set(idx, tmpSymbol);
                        Symbol to = instruction.getElementPtr(((MyArray) newSymbol), new MyNumber(idx));
                        instruction.store(tmpSymbol, to);
                        pos[depth]++;
                        if (token.equalTo(",")) {//逗号只会出现在右括号后面或者ConstExp后面
                            nextToken();
                        }
                    }
                } while (!match.empty());
                System.out.println("***debug数组内容：" + ((MyArray) newSymbol).getContent());
            } else {

            }
        } else {
            newSymbol = instruction.alloca(ident.value().toString()); // 分配内存，登记到符号表
            newSymbol.setConst(false); // 是变量
            newSymbol.setName(ident.value().toString());
            if (token.equalTo("=")) {
                nextToken();
                Symbol result = analyseInitVal(); // 得到计算结果
                instruction.store(result, newSymbol); //将计算结果存入目标
            }
        }
    }

    /**
     * InitVal      -> Exp
     *
     * @throws CompileError
     */
    private Symbol analyseInitVal() throws CompileError {
        return analyseExp();
    }

    /**
     * FuncDef      -> FuncType Ident '(' ')' Block
     * FuncDef      -> FuncType Ident '(' [FuncFParams] ')' Block
     *
     * @throws CompileError
     */
    private void analyseFuncDef() throws CompileError {
        String funcType = analyseFuncType();
        needRetExp = (funcType == "int");
        hasRet = false;
        String funcName = analyseIdent();
        ArrayList<Symbol> funcParams = null;
        llvm.append("@" + funcName);
        if (token.equalTo("(")) {
            Table.getInstance().addBlock();//进入一个块
            regCnt = 1;
            llvm.append("(");
            nextToken();
            if (!token.equalTo(")")) {//有参数
                funcParams = analyseFuncFParams();
            }// 否则无参数
            if (token.equalTo(")")) {
                if (funcParams != null && funcParams.size() != 0) {//形参输出llvm
                    String type = "i32";
                    if (funcParams.get(0) instanceof MyArray) {
                        type = "i32*";
                    }
                    llvm.append(type + " " + funcParams.get(0).getPrintAddr());
                    for (int i = 1; i < funcParams.size(); i++) {
                        type = "i32";
                        if (funcParams.get(i) instanceof MyArray) {
                            type = "i32*";
                        }
                        llvm.append(", " + type + " " + funcParams.get(i).getPrintAddr());
                    }
                }
                llvm.append(")");
                nextToken();
                llvm.append("{\n");
                if (funcParams != null) {
                    for (int i = 0; i < funcParams.size(); i++) {
                        Symbol symbol = funcParams.get(i);
                        instruction.alloca(symbol);//形参分配内存
                        Table.getInstance().addSymbol(symbol.getName(), symbol);
                    }
                }
                Function function = new Function(funcName, funcType, funcParams);
                Table.getInstance().addFunction(funcName, function);//加入函数表

                analyseBlock();
                if (!hasRet) {
                    if (needRetExp) {
                        llvm.append("\tret i32 0\n");
                    } else {
                        llvm.append("\tret void\n");
                    }
                }
                llvm.append("}\n");

            } else {
                throw new CompileError("期望)，实际为" + token);
            }
        } else {
            throw new CompileError("期望(，实际为" + token);
        }
    }


    /**
     * FuncType   -> 'int' | 'void'
     *
     * @throws CompileError
     */
    private String analyseFuncType() throws CompileError {
        if (token.equalTo("int")) {
            llvm.append("define dso_local i32 ");
            nextToken();
            return "int";
        } else if (token.equalTo("void")) {
            llvm.append("define dso_local void ");
            nextToken();
            return "void";
        } else {
            throw new CompileError("期望int，实际为" + token);
        }
    }

    private String analyseIdent() throws CompileError {
        if (token.type() == TokenType.Ident) {
            String tokenName = token.value().toString();
            nextToken();
            return tokenName;
        } else {
            throw new CompileError("期望标识符，实际为" + token);
        }
    }

    /**
     * Block        -> '{' { BlockItem } '}'
     *
     * @throws CompileError
     */
    private boolean analyseBlock() throws CompileError {
        boolean brOrCon = false;
        if (token.equalTo("{")) {
            nextToken();
            while (!token.equalTo("}")) {
                brOrCon = analyseBlockItem();
            }
            if (token.equalTo("}")) {
                nextToken();
                Table.getInstance().leaveBlock();//离开一个块
            } else {
                throw new CompileError("期望}，实际为" + token);
            }
        } else {
            throw new CompileError("期望{，实际为" + token);
        }
        return brOrCon;
    }

    /**
     * BlockItem    -> Decl | Stmt
     *
     * @throws CompileError
     */
    private boolean analyseBlockItem() throws CompileError {
        if (token.equalTo("const") || token.equalTo("int")) {
            analyseDecl();
            return false;
        } else {
            return analyseStmt();
        }
    }

    /**
     * Stmt -> LVal '=' Exp ';' | Block  | [Exp] ';'
     * | 'if' '(' Cond ')' Stmt [ 'else' Stmt ]
     * | 'return' [Exp] ';' // [changed]
     * | 'while' '(' Cond ')' Stmt
     * | 'break' ';'
     * | 'continue' ';'
     *
     * @return true表示遇到了continue、break
     * @throws CompileError
     */
    private boolean analyseStmt() throws CompileError {
        if (token.equalTo("while")) {// 'while' '(' Cond ')' Stmt
            nextToken();

            if (token.equalTo("(")) {
                nextToken();
                String condLabel = "l" + (Table.regCnt++),
                        trueLabel = "l" + (Table.regCnt++);
                instruction.br(condLabel); //从当前进入条件判断label
                instruction.labelBegin(condLabel);//开始条件判断

                ArrayList<Object> res = analyseCond(trueLabel);
                Symbol cond = (Symbol) res.get(0);

                String falseLabel = (String) res.get(1);

                if (token.equalTo(")")) {
                    nextToken();
                    instruction.br(cond, trueLabel, falseLabel);//跳转
                    instruction.labelBegin(trueLabel); // trueLabel开始，然后分析Stmt
                    //continue和break都是在while的stmt里面出现的，先进栈
                    continueStk.push(condLabel);// continue之后，重新条件判断，进入condLabel
                    breakStk.push(falseLabel);// 块break之后，离开，进入falseLabel
                    if (!analyseStmt())//没有break和continue
                        instruction.br(condLabel);//跳回condLabel再去判断
                    continueStk.pop();//while的stmt结束后出栈
                    breakStk.pop();
                    instruction.labelBegin(falseLabel); //falseLabel开始
                } else {
                    throw new CompileError("while期望)，实际为" + token);
                }

            } else {
                throw new CompileError("while期望(，实际为" + token);
            }
        } else if (token.equalTo("break")) {//'break' ';'
            nextToken();
            if (token.equalTo(";")) {
                nextToken();
                if (!breakStk.empty()) {
                    instruction.br(breakStk.peek());
                    return true;
                } else {
                    throw new CompileError("breakStack为空");
                }
            } else {
                throw new CompileError("break期望:，实际为" + token);
            }
        } else if (token.equalTo("continue")) { //'continue' ';'
            nextToken();
            if (token.equalTo(";")) {
                nextToken();
                if (!continueStk.empty()) {
                    instruction.br(continueStk.peek());
                    return true;
                } else {
                    throw new CompileError("continueStack为空");
                }
            } else {
                throw new CompileError("continue期望;，实际为" + token);
            }
        } else if (token.type() == TokenType.Ident) {
            // FIRST集含ident的有两个产生式
            String ident = token.value().toString();
            nextToken();
            if (token.equalTo("=") || token.equalTo("[")) {//LVal '=' Exp ';' 这种形式是变量赋值
                // 需要从符号表中找到这个变量才可以赋值
                backToLastToken();
                Symbol target = analyseLVal();
                if (token.equalTo("=")) {
                    nextToken();
                    Symbol result = analyseExp();
                    if (target.isConst())
                        throw new CompileError("常量不能多次赋值");
                    instruction.store(result, target);
                } else {
                    throw new CompileError("期望等号，实际为" + token);
                }
            } else {//[Exp] ';'
                backToLastToken();
                analyseExp();
            }
            if (token.equalTo(";")) {
                nextToken();
            } else {
                throw new CompileError("期望;，实际为" + token);
            }
        } else if (token.equalTo("{")) {//Block
            Table.getInstance().addBlock();//进入一个块
            return analyseBlock();
        } else if (token.equalTo("if")) {//if语句
            nextToken();
            if (token.equalTo("(")) {
                nextToken();
                String finalLabel = "l" + (Table.regCnt++);
                String trueLabel = "l" + (Table.regCnt++);

                ArrayList<Object> res = analyseCond(trueLabel);
                Symbol cond = (Symbol) res.get(0);
                String falseLabel = (String) res.get(1);

                if (token.equalTo(")")) {
                    nextToken();
                    instruction.br(cond, trueLabel, falseLabel); // 上个块的跳转命令
                    instruction.labelBegin(trueLabel); // trueLabel开始
                    boolean brOrCon = analyseStmt();
                    if (token.equalTo("else")) {
                        nextToken();
                        if (!brOrCon)//没有break和continue
                            instruction.br(finalLabel); // if有else，先让if跳转到final
                        instruction.labelBegin(falseLabel); //再让else的label开始
                        if (!analyseStmt())//没有break和continue
                            instruction.br(finalLabel); //else的label跳转到final
                        instruction.labelBegin(finalLabel); //final的Label开始
                        hasRet = false;
                    } else {
                        if (!brOrCon) {//没有break和continue
                            instruction.br(falseLabel); // if结束后，跳到false
                        }
                        instruction.labelBegin(falseLabel); // 让false开始
                        hasRet = false;
                    }
                } else {
                    throw new CompileError("期望)，实际为" + token);
                }
            } else {
                throw new CompileError("期望(，实际为" + token);
            }
        } else if (token.equalTo("return")) {//return语句
            hasRet = true;
            nextToken();
            if (!token.equalTo(";")) {//有返回值
                Symbol symbol = analyseExp();
                instruction.ret(symbol);
                if (!needRetExp)
                    throw new CompileError("当前函数无需返回值");
            } else {
                instruction.ret();
            }
            if (token.equalTo(";")) {
                nextToken();
            } else {
                throw new CompileError("期望;，实际为" + token);
            }
        } else if (token.equalTo(";")) {//单独一个分号
            nextToken();
        } else {//除去开头是Ident的Exp
            analyseExp();
            if (token.equalTo(";")) {
                nextToken();
            } else {
                throw new CompileError("期望;，实际为" + token);
            }
        }
        return false;
    }

    private Symbol analyseExp() throws CompileError {
        return analyseAddExp();
    }

    private ArrayList<Object> analyseCond(String trueLabel) throws CompileError {
//        Symbol symbol = analyseLOrExp();
//        return symbol;
        return analyseLOrExp(trueLabel);
    }

    /**
     * LAndExp {  '||' LAndExp  }
     *
     * @return
     * @throws CompileError
     */
    private ArrayList<Object> analyseLOrExp(String trueLabel) throws CompileError {
        String falseLabel = "l" + regCnt++;
        Symbol result = analyseLAndExp(falseLabel);
        if (result.isI32()) {
            result = instruction.icmp(result, new MyNumber(0), "!=");// ==对应的eq
        }
        while (token.equalTo("||")) {
            nextToken();
            instruction.br(result, trueLabel, falseLabel);
            instruction.labelBegin(falseLabel);
            falseLabel = "l" + regCnt++;
            result = analyseLAndExp(falseLabel);
//            Symbol next = analyseLAndExp(falseLabel);
//            result = instruction.operate(result, next, "||");
            if (result.isI32()) {
                result = instruction.icmp(result, new MyNumber(0), "!=");// ==对应的eq
            }
        }
        ArrayList<Object> res = new ArrayList<>();
        res.add(result);
        res.add(falseLabel);
        return res;
//        return result;
    }

    /**
     * EqExp { '&&' EqExp }
     *
     * @return
     * @throws CompileError
     */
    private Symbol analyseLAndExp(String falseLabel) throws CompileError {
        Symbol result = analyseEqExp();
        if (result.isI32()) {
            result = instruction.icmp(result, new MyNumber(0), "!=");// ==对应的eq
        }
        while (token.equalTo("&&")) {
            nextToken();
            String trueLabel = "l" + regCnt++;
            instruction.br(result, trueLabel, falseLabel);
            instruction.labelBegin(trueLabel);

            result = analyseEqExp();
//            Symbol next = analyseEqExp();
            if (result.isI32()) {
                result = instruction.icmp(result, new MyNumber(0), "!=");// ==对应的eq
            }
//            if (next.isI32()) {
//                next = instruction.icmp(next, new MyNumber(0), "!=");// ==对应的eq
//            }
//            result = instruction.operate(result, next, "&&");//计算结果再次赋给result

        }
        return result;
//        return result;
    }

    /**
     * LVal         -> Ident
     * LVal         -> Ident {'[' Exp ']'} // [changed]
     *
     * @return
     * @throws CompileError
     */
    private Symbol analyseLVal() throws CompileError {
        String ident = token.value().toString();
        if (token.type() == TokenType.Ident) {
            nextToken();
            if (token.equalTo("[")) {
                Symbol symbol = Table.getInstance().getSymbol(ident);
                if (symbol instanceof MyArray) {
                    MyArray array = (MyArray) symbol;
                    int dim_i = 0;//维度计数
                    ArrayList<Symbol> syms = new ArrayList<>();//该维度的位置
                    while (token.equalTo("[")) {
                        nextToken();
                        syms.add(analyseExp());//注意这里是exp可能出来不是数字！
                        if (token.equalTo("]")) {
                            nextToken();
                        } else {
                            throw new CompileError("期望]实际为" + token);
                        }
                        dim_i++;
                    }
                    Symbol result = new MyNumber(0);
                    int postMul = 1;
                    for (int i = array.getDim() - 1; i >= 0; i--) {// 后缀积
                        if (i < dim_i)
                            result = instruction.operate(instruction.operate(syms.get(i), new MyNumber(postMul), "*")
                                    , result, "+");
                        postMul *= array.getSize().get(i);
                    }
                    MyArray arrayRet = instruction.getElementPtr(array, result);
                    if (token.equalTo("=")) {
                        if (dim_i != array.getDim())
                            throw new CompileError("LVal=Exp获取数组元素时维度不匹配" + array);
                        return arrayRet; // 后面要赋值，不用load
                    }
                    arrayRet.setDimAndSize(array.getDim() - dim_i, array.getSize());
//                    return arrayRet;
                    if (arrayRet.getDim() == 0)
                        return instruction.load(arrayRet);
                    else {
                        return arrayRet;
                    }
                } else {
                    throw new CompileError("不知道为什么出错了/(ㄒoㄒ)/~~");
                }
            } else {
                Symbol symbol = Table.getInstance().getSymbol(ident);
                if (symbol instanceof MyArray) {
                    symbol = instruction.getElementPtr((MyArray) symbol, new MyNumber(0));
                }
                return symbol;
            }
        } else {
            throw new CompileError("期待Ident，实际为" + token);
        }
    }

    /**
     * PrimaryExp   -> '(' Exp ')' | LVal | Number
     *
     * @return
     * @throws CompileError
     */
    private Symbol analysePrimaryExp() throws CompileError {
        Symbol symbol = null;
        if (token.equalTo("(")) {
            nextToken();
            symbol = analyseExp();
            if (token.equalTo(")")) {
                nextToken();
            } else {
                throw new CompileError("期望)，实际为" + token);
            }
        } else if (token.type() == TokenType.Ident) {
            Symbol lVal = analyseLVal();
            if (lVal instanceof MyArray) {
                symbol = lVal;
            } else if (!(lVal instanceof MyNumber)) {
                symbol = instruction.load(lVal);
            }
        } else if (token.type() == TokenType.Number) {
            symbol = new MyNumber((Integer) token.value());
            nextToken();
        }
        return symbol;
    }

    /**
     * UnaryExp     -> PrimaryExp  | Ident '(' [FuncRParams] ')' | UnaryOp UnaryExp
     *
     * @return
     * @throws CompileError
     */
    private Symbol analyseUnaryExp() throws CompileError {
        Symbol result;
        String op = token.value().toString();
        if (token.equalTo("(") || token.type() == TokenType.Number) {
            return analysePrimaryExp();
        } else if (token.type() == TokenType.Ident) {// Func的ident或者primaryExp的LVal的Ident
            String funcName = token.value().toString();
            nextToken();
            if (token.equalTo("(")) {
                nextToken();
                result = new Symbol("%v" + (Table.regCnt++));
                if (token.equalTo(")")) {//没有参数
                    nextToken();
                    if (funcName.equals("getint")) {
                        llvm.append("\t" + result.getAddress() + " = call i32 @getint()\n");
                    } else if (funcName.equals("getch")) {
                        llvm.append("\t" + result.getAddress() + " = call i32 @getch()\n");
                    } else {
                        Function function = Table.getInstance().getFunction(funcName);
                        if (function.getParams() != null && function.getParams().size() != 0) {
                            throw new CompileError(funcName + "函数调用需要参数");
                        } else {
                            if (function.getType().equals("int")) {//%2 = call i32 @func1()
                                result = new Symbol("%v" + regCnt++);
                                llvm.append("\t" + result.getAddress() + " = call i32 @" + funcName + "()\n");
                            } else {//void
                                llvm.append("\tcall void @" + funcName + "()\n");
                            }
                        }
                    }
                } else {
                    result = analyseFuncRParams(funcName);
                    if (token.equalTo(")")) {
                        nextToken();
                    } else {
                        throw new CompileError("含参函数" + funcName + "缺少右括号");
                    }
                }
                return result;
            } else {
                backToLastToken();
                return analysePrimaryExp();
            }
        } else if (isUnaryOp()) {
            Symbol next = analyseUnaryExp();
            if (op.equals("!")) {
                if (next.isI32()) {
                    result = instruction.icmp(next, new MyNumber(0), "==");
                } else {// 是i1，就转为i32
                    Symbol tmp = instruction.zext(next);
                    result = instruction.icmp(tmp, new MyNumber(0), "==");
                }
            } else {// + 或者 - ，操作对象应该是i32
                if (next.isI32()) {
                    result = instruction.operate(new MyNumber(0), next, op);
                } else {// 先转为i32
                    Symbol tmp = instruction.zext(next);
                    result = instruction.operate(new MyNumber(0), tmp, op);
                }
            }
        } else {
            throw new CompileError("非法的UnaryExp" + token);
        }
        return result;
    }

    private boolean isUnaryOp() throws CompileError {
        if (token.equalTo("+") || token.equalTo("-") || token.equalTo("!")) {
            nextToken();
            return true;
        }
        return false;
    }

    /**
     * FuncRParams  -> Exp { ',' Exp }
     *
     * @throws CompileError
     */
    private Symbol analyseFuncRParams(String funcName) throws CompileError {
        Symbol result = null;
        ArrayList<Symbol> funcParams = new ArrayList<>();//调用函数时传递的参数
        funcParams.add(analyseExp());
//        Symbol symbol = analyseExp();
        while (token.equalTo(",")) {
            nextToken();
//            analyseExp();
            funcParams.add(analyseExp());
        }
        if (funcName.equals("putint") && funcParams.size() == 1) {//一个参数
            llvm.append("\tcall void @putint(i32 " + funcParams.get(0).getPrintAddr() + ")\n");
        } else if (funcName.equals("putch") && funcParams.size() == 1) {
            llvm.append("\tcall void @putch(i32 " + funcParams.get(0).getPrintAddr() + ")\n");
        } else if (funcName.equals("getarray") && funcParams.size() == 1) {//int getarray(int []);
            Symbol symbol = funcParams.get(0);//是一个数组对象的地址
            result = new Symbol("%v" + Table.regCnt++);
            //%8 = call i32 @getarray(i32* %7)
            llvm.append("\t" + result.getAddress() + " = call i32 @getarray(i32* " + symbol.getAddress() + ")\n");
        } else if (funcName.equals("putarray") && funcParams.size() == 2) {//void putarray(int, int[]);
            //call void @putarray(i32 %29, i32* %33)
            llvm.append("\tcall void @putarray(i32 " + funcParams.get(0).getPrintAddr() + ", i32* " + funcParams.get(1).getAddress() + ")\n");
        } else {//非库函数
            Function function = Table.getInstance().getFunction(funcName);
            int length = function.getParams().size();
            if (length != funcParams.size())
                throw new CompileError("传递的参数和定义参数长度不匹配");
            for (int i = 0; i < length; i++) {
                Symbol need = function.getParams().get(i), real = funcParams.get(i);
                if (need instanceof MyArray) {
                    if (real instanceof MyArray) {
                        if (((MyArray) need).getDim() != ((MyArray) real).getDim()) {
                            throw new CompileError("传递的数组和所需数组维度不匹配" + function + "real:" + real + "need:" + need);
                        }
                    } else {
                        throw new CompileError("期望传递数组" + function + "real:" + real + "need:" + need);
                    }
                } else {
                    if (real instanceof MyArray && ((MyArray) real).getDim() != 0) {
                        throw new CompileError("所需非数组\n" + function + token + "real:" + real + "need:" + need);
                    }
                }
            }

            if (function.getType() == "int") {//%4 = call i32 @func2()
                result = new Symbol("%v" + Table.regCnt++);
                llvm.append("\t" + result.getAddress() + " = call i32 @" + funcName + "(");
            } else {//call void @set1(i32 %19, i32* %25)
                llvm.append("\tcall void @" + funcName + "(");
            }
            String type = "i32";
            if (funcParams.get(0) instanceof MyArray && ((MyArray) funcParams.get(0)).getDim() != 0) {
                type = "i32*";
            }
            llvm.append(type + " " + funcParams.get(0).getPrintAddr());
            for (int i = 1; i < length; i++) {
                type = "i32";
                if (funcParams.get(i) instanceof MyArray && ((MyArray) funcParams.get(i)).getDim() != 0) {
                    type = "i32*";
                }
                llvm.append(", " + type + " " + funcParams.get(i).getPrintAddr());
            }
            llvm.append(")\n");
        }
        return result;
    }

    /**
     * FuncFParams  -> FuncFParam { ',' FuncFParam }
     *
     * @return
     * @throws CompileError
     */
    private ArrayList<Symbol> analyseFuncFParams() throws CompileError {
        ArrayList<Symbol> funcParams = new ArrayList<>();
        funcParams.add(analyseFuncParam());
        while (token.equalTo(",")) {
            nextToken();
            funcParams.add(analyseFuncParam());
        }
        return funcParams;
    }

    //FuncFParam   -> BType Ident ['[' ']' { '[' Exp ']' }] // [new]
    private Symbol analyseFuncParam() throws CompileError {
        analyseBType();
        String identName = analyseIdent();
        if (token.equalTo("[")) {//是数组
            nextToken();
            if (token.equalTo("]")) {
                nextToken();
            } else {
                throw new CompileError("函数参数数组期望]，实际为" + token);
            }
            ArrayList<Integer> size = new ArrayList<>();
            size.add(0);
            while (token.equalTo("[")) {
                nextToken();
                size.add(analyseGlobalExp(false));//计算当前维度的长度，要求是常量表达式
                if (token.equalTo("]")) {
                    nextToken();
                } else {
                    throw new CompileError("函数参数期望]，实际为" + token);
                }
            }
            return new MyArray(identName, "%a" + Table.regCnt++, size);
        } else {
            return new Symbol(identName, "%v" + Table.regCnt++, "i32");
        }
    }

    /**
     * AddExp       -> MulExp { ('+' | '-') MulExp }
     *
     * @return
     * @throws CompileError
     */
    private Symbol analyseAddExp() throws CompileError {
        Symbol result = analyseMulExp();
        while (token.equalTo("+") || token.equalTo("-")) {
            String op = token.value().toString();
            nextToken();
            Symbol next = analyseMulExp();
            result = instruction.operate(result, next, op);//计算结果再给result
        }
        return result;
    }

    /**
     * UnaryExp{ ('*' | '/' | '%') UnaryExp }
     *
     * @return
     * @throws CompileError
     */
    private Symbol analyseMulExp() throws CompileError {
        Symbol result = analyseUnaryExp();
        while (token.equalTo("*") || token.equalTo("/") || token.equalTo("%")) {
            String op = token.value().toString();
            nextToken();
            Symbol next = analyseUnaryExp();
            result = instruction.operate(result, next, op);
        }
        return result;
    }


    /**
     * RelExp { ('==' | '!=') RelExp }
     *
     * @return
     * @throws CompileError
     */
    private Symbol analyseEqExp() throws CompileError {
        Symbol result = analyseRelExp();
        while (token.equalTo("==") || token.equalTo("!=")) {
            String op = token.value().toString();
            nextToken();
            Symbol next = analyseRelExp();
            //12计算结果给1
            result = instruction.icmp(result, next, op);
        }
        return result;
    }

    /**
     * AddExp { ('<' | '>' | '<=' | '>=') AddExp }
     *
     * @return
     * @throws CompileError
     */
    private Symbol analyseRelExp() throws CompileError {
        Symbol result = analyseAddExp();
        while (token.equalTo("<") || token.equalTo(">") || token.equalTo("<=") || token.equalTo(">=")) {
            String op = token.value().toString();
            nextToken();
            Symbol next = analyseAddExp();
            result = instruction.icmp(result, next, op);
        }
        return result;
    }

    /**
     * globalDecl -> [const] int globalDef { , globalDef } ;
     *
     * @throws CompileError
     */
    private void analyseGlobalDecl() throws CompileError {
        boolean isConst = false;
        if (token.equalTo("const")) {
            nextToken();
            isConst = true;
        }
        if (token.equalTo("int")) {
            nextToken();
            analyseGlobalDef(isConst);
            while (token.equalTo(",")) {
                nextToken();
                analyseGlobalDef(isConst);
            }
            if (token.equalTo(";")) {
                nextToken();
            } else {
                throw new CompileError("期望;，实际为" + token);
            }
        } else {
            throw new CompileError("期望int，实际为" + token);
        }
    }

    /**
     * @param isConst 语法 globalDef -> ident  = globalExp | ident
     *                <p>
     *                Ident { '[' ConstExp ']' } '=' ConstInitVal
     *                ConstInitVal -> ConstExp  | '{' [ ConstInitVal { ',' ConstInitVal } ] '}'
     * @throws CompileError
     */
    private void analyseGlobalDef(boolean isConst) throws CompileError {
        if (token.type() == TokenType.Ident) {
            String identName = token.value().toString();
            nextToken();
            if (token.equalTo("[")) {// 数组
                int dim = 0, length = 1;
                ArrayList<Integer> size = new ArrayList<>();
                while (token.equalTo("[")) {
                    nextToken();
                    int value = analyseGlobalExp(false); // 用计算常量表达式的函数
                    if (value < 0)
                        throw new CompileError("数组下标为负值" + value);
                    size.add(value);
                    length *= value;
                    dim++;
                    if (token.equalTo("]")) {
                        nextToken();
                    } else {
                        throw new CompileError("期望]，实际为" + token);
                    }
                }// a[2][2][3]={{{1,2,3},{4,5,6}},{{1,2,3},{4,5,6}}}的a[2][2][3]结束
                MyArray array = new MyArray("@g" + Table.regCnt++);
                array.setConst(isConst);
                array.setGlobal(true);
                array.setName(identName);
                array.setDimAndSize(dim, size);
                if (token.equalTo("=")) {
                    nextToken();
                    ArrayList<Symbol> content = array.getContent();
                    int depth = -1;
                    int[] pos = new int[dim];
                    Arrays.fill(pos, -1);
                    Stack<String> match = new Stack<>();
                    do {
                        if (token.equalTo("{")) {
                            nextToken();
                            depth++;
                            pos[depth]++;
                            match.push("{");
                        } else if (token.equalTo("}")) {
                            depth--;
                            if (depth != -1) {//不是最外围
                                pos[depth]++;
                            }
                            Arrays.fill(pos, depth + 1, dim, -1);//退回一维后面的重置为-1重新计数
                            if (match.peek().equals("{")) {
                                match.pop();
                            } else {
                                throw new CompileError("右括号与左括号不匹配" + token);
                            }
                            nextToken();
                            if (match.empty()) {
                                break;
                            }
                            if (token.equalTo(",")) {//逗号只会出现在右括号后面或者ConstExp后面
                                nextToken();
                            }
                        } else {
                            if (depth == dim - 1) {
                                int value = analyseGlobalExp(false);
                                MyNumber tmpSymbol = new MyNumber(value);
                                int idx = 0, postMul = 1;
                                for (int i = dim - 1; i >= 0; i--) {
                                    idx += pos[i] * postMul;
                                    postMul *= size.get(i);
                                }
                                content.set(idx, tmpSymbol);
                                pos[depth]++;
                                if (token.equalTo(",")) {//逗号只会出现在右括号后面或者ConstExp后面
                                    nextToken();
                                }
                            } else {
                                throw new CompileError("数组维度不对！" + array.getName());
                            }
                        }
                    } while (!match.empty());
                    instruction.setGlobal(array, false);
                    System.out.println("***debug数组内容：" + array.getContent());
                } else {//默认是0
                    // 前面setDimAndSize的时候已经处理过了
                    instruction.setGlobal(array, true);
                }

            } else {// 非数组
                Symbol symbol = new Symbol("@g" + Table.regCnt++);
                symbol.setConst(isConst);
                symbol.setGlobal(true);
                symbol.setName(identName);
                if (token.equalTo("=")) {
                    nextToken();
                    int value = analyseGlobalExp(true);
                    symbol.setInitVal(value);
                } else {// 没有赋值就默认是0
                    symbol.setInitVal(0);
                }
                instruction.setGlobal(symbol, false); // 加入全局表，输出llvm
            }

        } else {
            throw new CompileError("期望ident，实际为" + token);
        }
    }

    /**
     * @return global -> globalAddExp
     */
    private int analyseGlobalExp(boolean isGlobal) throws CompileError {
        return analyseGlobalAddExp(isGlobal);
    }

    /**
     * @return globalAddExp -> globalMulExp { +|-  globalMulExp }
     * @throws CompileError
     */
    private int analyseGlobalAddExp(boolean isGlobal) throws CompileError {
        int res = analyseGlobalMulExp(isGlobal);
        while (token.equalTo("+") || token.equalTo("-")) {
            String op = token.value().toString();
            nextToken();
            int next = analyseGlobalMulExp(isGlobal);
            if (op.equals("+"))
                res += next;
            else
                res -= next;
        }
        return res;
    }

    /**
     * @return globalMulExp -> globalUnaryExp { *|/|%  globalUnaryExp }
     * @throws CompileError
     */
    private int analyseGlobalMulExp(boolean isGlobal) throws CompileError {
        int res = analyseGlobalUnaryExp(isGlobal);
        while (token.equalTo("*") || token.equalTo("/") || token.equalTo("%")) {
            String op = token.value().toString();
            nextToken();
            int next = analyseGlobalUnaryExp(isGlobal);
            if (op.equals("*"))
                res *= next;
            else if (op.equals("/"))
                res /= next;
            else
                res %= next;
        }
        return res;
    }

    /**
     * globalUnaryExp -> (globalExp) | Ident | Number | +或- globalUnaryExp
     *
     * @return
     * @throws CompileError
     */
    private int analyseGlobalUnaryExp(boolean isGlobal) throws CompileError {
        int result;
        if (token.equalTo("(")) {
            nextToken();
            result = analyseGlobalExp(isGlobal);
            if (token.equalTo(")"))
                nextToken();
            else {
                throw new CompileError("期望)，实际为" + token);
            }
        } else if (token.type() == TokenType.Ident) {
            String identName = token.value().toString();
            nextToken();
            if (isGlobal) {
                Symbol globalSymbol = Table.getInstance().getGlobal(identName);
                if (globalSymbol.isConst())
                    result = globalSymbol.getInitVal();
                else {
                    throw new CompileError("全局量定义不合法，非const类型" + globalSymbol);
                }
            } else {
                Symbol symbol = Table.getInstance().getSymbol(identName);
                if (symbol.isConst()) {
                    result = symbol.getInitVal();
                } else {
                    throw new CompileError("非const类型" + symbol);
                }
            }

        } else if (token.type() == TokenType.Number) {
            result = (int) token.value();
            nextToken();
        } else if (token.equalTo("+")) {
            nextToken();
            result = analyseGlobalUnaryExp(isGlobal);
        } else if (token.equalTo("-")) {
            nextToken();
            result = -analyseGlobalUnaryExp(isGlobal);
        } else {
            throw new CompileError("全局变量定义不合法符号" + token);
        }
        return result;
    }


}
